home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / pmlpp140.zip / SRC / pop.c < prev    next >
C/C++ Source or Header  |  1997-07-30  |  12KB  |  529 lines

  1. /*
  2. PMLPP - A POP3 mail "peeker" for OS/2<tm>.
  3. Copyright (C) 1997 James R. Louvau
  4.  
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. You may contact the author of PMLPP at:
  20.  
  21. E-mail     : jim@vwm.com
  22. Snail-mail : Jim Louvau
  23.              3437 335th St.
  24.              West Des Moines, IA 50266
  25. */
  26.  
  27. #include "pmlpp.h"
  28.  
  29. #include <process.h>
  30. #include <time.h>
  31. #include <stdarg.h>
  32.  
  33. #pragma  pack(1)
  34.  
  35. #include <types.h>
  36. #include <sys\socket.h>
  37. #include <netdb.h>
  38. #include <utils.h>
  39. #include <netinet\in.h>
  40. #include <sys\ioctl.h>
  41.  
  42. #include "md5.h"
  43.  
  44. #pragma  pack()
  45.  
  46. #ifdef DEBUG
  47. static void
  48. LogErr( char * fmt,
  49.         ...        )
  50. /******************/
  51. {
  52.    struct sockaddr_in sin = { 0 };
  53.    int                sock;
  54.  
  55.    sock = socket( PF_INET, SOCK_DGRAM, 0 );
  56.    if ( sock < 0 )
  57.    {
  58.       return;
  59.    }
  60.  
  61.    sin.sin_family      = AF_INET;
  62.    sin.sin_port        = htons( 514 );
  63.    sin.sin_addr.s_addr = INADDR_ANY;
  64.  
  65.    if ( connect( sock, ( struct sockaddr * ) &sin, sizeof( sin )) >= 0 )
  66.    {
  67.       char                 buf[ 100 ];
  68.       char               * p;
  69.       va_list              ap;
  70.       time_t               now;
  71.  
  72.       time( &now );
  73.  
  74.       p = buf;
  75.  
  76.       p += sprintf( p, "<3>%.15s PMLPP: ", ctime( &now ) + 4 );
  77.  
  78.       va_start( ap, fmt );
  79.       p += vsprintf( p, fmt, ap );
  80.       va_end( ap );
  81.  
  82.       *p = '\0';
  83.  
  84.       send( sock, buf, strlen( buf ) + 1, 0 );
  85.    }
  86.    
  87.    soclose( sock );
  88. }
  89. #endif /* DEBUG */
  90.  
  91. static int
  92. Transact( int      sock,
  93.           char   * obuf,
  94.           char   * ibuf,
  95.           int      ilen )
  96. /***********************/
  97. {
  98.    static char   buffer[ 4096 ];
  99.    static char * bufptr = buffer;
  100.    static char * bufend = buffer;
  101.    int           bytes;
  102.    int           socks[ 1 ];
  103.  
  104.    if (( obuf != NULL ) && *obuf )
  105.    {
  106.       int olen = strlen( obuf );
  107.  
  108.       if (( ioctl( sock, FIONREAD, ( caddr_t ) &bytes, sizeof( bytes )) >= 0 ) && bytes )
  109.       {
  110.          for ( ; ; )
  111.          {
  112.             socks[ 0 ] = sock;
  113.  
  114.             if ( select( socks, 1, 0, 0, 500 ) <= 0 )
  115.             {
  116.                break;
  117.             }
  118.  
  119.             if ( recv( sock, buffer, sizeof( buffer ), 0 ) <= 0 )
  120.             {
  121.                break;
  122.             }
  123.          }
  124.       }
  125.  
  126.       while ( olen > 0 )
  127.       {
  128.          bytes = send( sock, obuf, olen, 0 );
  129.          if ( bytes <= 0 )
  130.          {
  131. #ifdef DEBUG
  132.             LogErr(  "Transact()::send() returned %d", sock_errno( ));
  133. #endif
  134.             return ( bytes );
  135.          }
  136.  
  137.          olen -= bytes;
  138.          obuf += bytes;
  139.       }
  140.    }
  141.  
  142.    if (( ibuf != NULL ) && ( ilen > 0 ))
  143.    {
  144.       int    c;
  145.       int    lastc = '\0';
  146.       char * iptr  = ibuf;
  147.  
  148.       bufptr = bufend = buffer;
  149.  
  150.       *iptr = '\0';
  151.  
  152.       while ( --ilen > 0 )
  153.       {
  154.          if ( bufptr == bufend )
  155.          {
  156.             bytes = recv( sock, buffer, sizeof( buffer ), 0 );
  157.             if ( bytes <= 0 )
  158.             {
  159. #ifdef DEBUG
  160.                LogErr(  "Transact()::recv() returned %d", sock_errno( ));
  161. #endif
  162.                *iptr = '\0';
  163.                return ( bytes );
  164.             }
  165.  
  166.             bufptr = buffer;
  167.             bufend = buffer + bytes;
  168.          }
  169.  
  170.          c = *bufptr++;
  171.  
  172.          if (( c == '\r' ) || ( c == '\0' ))
  173.          {
  174.             lastc = c;
  175.             ++ilen;
  176.             continue;
  177.          }
  178.  
  179.          if (( c == '\n' ) && ( lastc == '\r' ))
  180.          {
  181.             lastc = '\n';
  182.             break;
  183.          }
  184.  
  185.          lastc = c;
  186.          *iptr++ = c;
  187.       }
  188.  
  189.       *iptr = '\0';
  190.  
  191.       if ( lastc != '\n' )
  192.       {
  193.          for ( ; ; )
  194.          {
  195.             socks[ 0 ] = sock;
  196.  
  197.             if ( select( socks, 1, 0, 0, 500 ) <= 0 )
  198.             {
  199.                break;
  200.             }
  201.  
  202.             if ( recv( sock, buffer, sizeof( buffer ), 0 ) <= 0 )
  203.             {
  204.                break;
  205.             }
  206.          }
  207.       }
  208.  
  209.       return ( *ibuf );
  210.    }
  211.  
  212.    return ( '+' );
  213. }
  214.  
  215. static BOOL
  216. Logon( PSZ     pszSrvr,
  217.        PCONFIG pcfg    )  
  218. /**********************/
  219. {
  220.    CHAR szBuf[ 512 ];
  221.    int  tries;
  222.  
  223.    if ( ! pcfg->bNoAPOP )
  224.    {
  225.       char * p;
  226.  
  227.       p = strchr( pszSrvr, '<' );
  228.       if ( p != NULL )
  229.       {
  230.          strcpy( szBuf, p );
  231.  
  232.          p = strchr( szBuf, '>' );
  233.          if ( p != NULL )
  234.          {
  235.             MD5_CTX   context;
  236.             int       n;
  237.  
  238.             *( p + 1 ) = '\0';
  239.  
  240.             strcat( szBuf, pcfg->szPassword );
  241.  
  242.             MD5Init( &context );
  243.             MD5Update( &context, szBuf, strlen( szBuf ));
  244.             MD5Final( &context );
  245.  
  246.             p = szBuf;
  247.  
  248.             p += sprintf( p, "APOP %s ", pcfg->szUser );
  249.  
  250.             for ( n = 0; n < 16; n++ )
  251.             {
  252.                p += sprintf( p, "%02.2x", context.digest[ n ] );
  253.             }
  254.  
  255.             sprintf( p, "\r\n" );
  256.  
  257.             if ( Transact( pcfg->sock, szBuf, szBuf, sizeof( szBuf )) == '+' )
  258.             {
  259.                return ( TRUE );
  260.             }
  261.          }
  262.       }
  263.    }
  264.  
  265.    pcfg->bNoAPOP = TRUE;
  266.  
  267.    for ( tries = 0; tries < 2; tries++ )
  268.    {
  269.       sprintf( szBuf, "USER %s\r\n", pcfg->szUser );
  270.  
  271.       if ( Transact( pcfg->sock, szBuf, szBuf, sizeof( szBuf )) == '+' )
  272.       {
  273.          sprintf( szBuf, "PASS %s\r\n", pcfg->szPassword );
  274.       
  275.          if ( Transact( pcfg->sock, szBuf, szBuf, sizeof( szBuf )) == '+' )
  276.          {
  277.             return ( TRUE );
  278.          }
  279. #ifdef DEBUG
  280.          else
  281.          {
  282.             LogErr(  "Logon()[PASS] got \"%s\"", szBuf );
  283.          }
  284. #endif
  285.       }
  286. #ifdef DEBUG
  287.       else
  288.       {
  289.          LogErr(  "Logon()[USER] got \"%s\"", szBuf );
  290.       }
  291. #endif
  292.    }
  293.  
  294.    pcfg->bNoAPOP = FALSE;
  295.  
  296.    return ( FALSE );
  297. }
  298.  
  299. static long
  300. GetMsgCnt( PCONFIG pcfg )
  301. /***********************/
  302. {
  303.    struct sockaddr_in   sa  = { 0 };
  304.    struct linger        sol = { 1, 15 };
  305.    struct hostent     * he;
  306.    CHAR                 szBuf[ 512 ];
  307.    long                 lMsgCnt = 0;
  308.    int                  noblock;
  309.    u_long               ip = 0;
  310.  
  311.    sa.sin_family = AF_INET;
  312.  
  313.    if ( pcfg->usPort != 0 )
  314.    {
  315.       sa.sin_port   = htons( pcfg->usPort );
  316.    }
  317.    else
  318.    {
  319.       struct servent * pse = getservbyname( "pop3", "tcp" );
  320.       if ( pse == NULL )
  321.       {
  322.          sa.sin_port = htons( 110 );
  323.       }
  324.       else
  325.       {
  326.          sa.sin_port = pse->s_port;
  327.       }
  328.    }
  329.    
  330.    he = gethostbyname( pcfg->szServer );
  331.    if ( he == NULL )
  332.    {
  333.       ip = inet_addr( pcfg->szServer );
  334.  
  335.       he = gethostbyaddr(( char * ) &ip, sizeof( ip ), AF_INET );
  336.       if ( he == NULL )
  337.       {
  338.          if  (( ip == 0 ) || ( ip == 0xffffffff ) || ( ! pcfg->bForceIP ))
  339.          {
  340. #ifdef DEBUG
  341.             LogErr( "GetMsgCnt()::gethostby*() returned %d", sock_errno( ));
  342. #endif
  343.             return ( -1 ); /* can't resolve address */
  344.          }
  345.       }
  346.    }
  347.  
  348.    if ( he != NULL )
  349.    {
  350.       sa.sin_addr.s_addr = *(( u_long * ) he->h_addr );
  351.    }
  352.    else
  353.    {
  354.       /* 
  355.        * Use raw IP even though DNS lookup failed.
  356.        * Only happens if bForceIP is TRUE.
  357.        */
  358.       sa.sin_addr.s_addr = ip;
  359.    }
  360.  
  361.    pcfg->sock = socket( PF_INET, SOCK_STREAM, 0 );
  362.    if ( pcfg->sock == ( -1 ))
  363.    {
  364. #ifdef DEBUG
  365.       LogErr(  "GetMsgCnt()::socket() returned %d", sock_errno( ));
  366. #endif
  367.       return ( -2 ); /* no socket */
  368.    }
  369.  
  370.    setsockopt( pcfg->sock, SOL_SOCKET, SO_LINGER, ( char * ) &sol, sizeof( sol ));
  371.  
  372.    noblock = 0;
  373.    ioctl( pcfg->sock, FIONBIO, ( caddr_t ) &noblock, sizeof( noblock ));
  374.  
  375.    if ( connect( pcfg->sock, ( struct sockaddr * ) &sa, sizeof( sa )) >= 0 )
  376.    {
  377.       if ( Transact( pcfg->sock, NULL, szBuf, sizeof( szBuf )) == '+' )
  378.       {
  379.          if ( Logon( szBuf, pcfg ))
  380.          {
  381.             if ( Transact( pcfg->sock, "STAT\r\n", szBuf, sizeof( szBuf )) == '+' )
  382.             {
  383.                char * p;
  384.  
  385.                p = strchr( szBuf, ' ' );
  386.                if ( p != NULL )
  387.                {
  388.                   lMsgCnt = strtol( p, NULL, 10 );
  389.                }
  390.  
  391.                Transact( pcfg->sock, "QUIT\r\n", szBuf, sizeof( szBuf ));
  392.             }
  393.             else
  394.             {
  395. #ifdef DEBUG
  396.                LogErr(  "GetMsgCnt()::Transact()[STAT] got \"%s\"", szBuf );
  397. #endif
  398.                lMsgCnt = ( -7 ); /* STAT failed */
  399.             }
  400.          }
  401.          else
  402.          {
  403.             lMsgCnt = ( -6 );
  404.          }
  405.       }
  406.       else
  407.       {
  408. #ifdef DEBUG
  409.          LogErr(  "GetMsgCnt()::Transact()[connecting] got \"%s\"", szBuf ); 
  410. #endif
  411.          lMsgCnt = ( -4 ); /* server won't talk to us */
  412.       }
  413.    }
  414.    else
  415.    {
  416. #ifdef DEBUG
  417.       LogErr(  "GetMsgCnt()::connect() returned %d", sock_errno( ));
  418. #endif
  419.       lMsgCnt = ( -3 ); /* no connect */
  420.    }
  421.  
  422.    soclose( pcfg->sock );
  423.    pcfg->sock = ( -1 );
  424.  
  425.    return ( lMsgCnt );
  426. }
  427.  
  428. static void
  429. PollThread( void * pvParm )
  430. /*************************/
  431. {
  432.    PCONFIG pcfg = ( PCONFIG ) pvParm;
  433.    ULONG   ulJunk;
  434.    LONG    cbMsgs;
  435.    HAB     hab;
  436.  
  437.    hab = WinInitialize( 0 );
  438.  
  439.    pcfg->bAlive = TRUE;
  440.  
  441.    while ( pcfg->bAlive )
  442.    {
  443.       if (( DosWaitEventSem( pcfg->hev, SEM_INDEFINITE_WAIT ) != NO_ERROR ) ||
  444.            ( ! pcfg->bAlive )) 
  445.       {
  446.          continue;
  447.       }
  448.  
  449.       cbMsgs = GetMsgCnt( pcfg );
  450.  
  451.       WinPostMsg( pcfg->hwndNotify, WM_USER, MPFROMLONG( cbMsgs ), MPVOID );
  452.  
  453.       DosResetEventSem( pcfg->hev, &ulJunk );
  454.    }
  455.  
  456.    WinTerminate( hab );
  457.  
  458.    _endthread( );
  459. }
  460.  
  461. BOOL
  462. StartPolling( PCONFIG pcfg )
  463. /**************************/
  464. {
  465.    if ( pcfg->bAlive )
  466.    {
  467.       return ( TRUE );
  468.    }
  469.  
  470.    if ( DosCreateEventSem( NULL, &( pcfg->hev ), DC_SEM_SHARED, TRUE ) == NO_ERROR )
  471.    {
  472.       if ( DosStartTimer( 1000L * pcfg->ulInterval, ( HSEM ) pcfg->hev, &( pcfg->htimer ))
  473.            == NO_ERROR )
  474.       {
  475.          pcfg->tid = _beginthread( PollThread, NULL, THREADSTKSZ, pcfg );
  476.          if ( pcfg->tid != ( -1 ))
  477.          {
  478.             return ( TRUE );
  479.          }
  480.  
  481.          DosStopTimer( pcfg->htimer );
  482.       }
  483.  
  484.       DosCloseEventSem( pcfg->hev );
  485.    }
  486.  
  487.    return ( FALSE );
  488. }
  489.  
  490. void
  491. StopPolling( PCONFIG pcfg )
  492. /*************************/
  493. {
  494.    if ( ! pcfg->bAlive )
  495.    {
  496.       return;
  497.    }
  498.  
  499.    DosSuspendThread( pcfg->tid );
  500.  
  501.    pcfg->bAlive = FALSE;
  502.  
  503.    DosPostEventSem( pcfg->hev );
  504.  
  505.    if ( pcfg->sock != ( -1 ))
  506.    {
  507.       so_cancel( pcfg->sock );
  508.       shutdown( pcfg->sock, 2 );
  509.    }
  510.  
  511.    DosResumeThread( pcfg->tid );
  512.  
  513.    DosWaitThread( &( pcfg->tid ), DCWW_WAIT );
  514.  
  515.    DosStopTimer( pcfg->htimer );
  516.    DosCloseEventSem( pcfg->hev );
  517. }
  518.  
  519. void
  520. PollNow( PCONFIG pcfg )
  521. /*********************/
  522. {
  523.    if ( pcfg->bAlive )
  524.    {
  525.       DosPostEventSem( pcfg->hev );
  526.    }
  527. };
  528.  
  529.